package com.metka.volidata.aop;

import com.metka.volidata.annotation.Valid;
import com.metka.volidata.annotation.Valids;
import com.metka.volidata.exception.ValidIllegalArgumentException;
import com.metka.volidata.util.ReflectUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: Metka499
 * @Description:
 * @CreateTime: 2020/7/6 16:35
 */

@Component
@Aspect
public class ParamValidationAspect {

    @Pointcut("@annotation(com.metka.volidata.annotation.Valids)")
    public void paramValidationAspect() {
    }

    @Around("paramValidationAspect()")
    public Object around(ProceedingJoinPoint point) throws Throwable {

        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();

        //key 参数名  value 实际对象
        Map<String, Object> requestParamMaps = new HashMap<>();
        //映射参数名 跟 实际对象
        Object[] requestParam = point.getArgs();
        Parameter[] parameters = method.getParameters();
        for (int i = 0, len = parameters.length; i < len; i++) {
            requestParamMaps.put(parameters[i].getName(), requestParam[i]);
        }

        //获取Valid注解
        Valids validsAnnotation = method.getAnnotation(Valids.class);
        for (Valid valid : validsAnnotation.value()) {
            //获取校验哪个参数 user.order.id
            /*
              先从map中获取user对象，然后再通过getOrder.getId原则
             */
            String name = valid.name(); //user.order.id

            //获取真正需要验证的对象  id
            Object validObj = parseValidObj(name, requestParamMaps);
            valid(validObj, valid);
        }
        Object result = point.proceed();
        return result;
    }

    /**
     * 通过valid注解上的参数属性 校验对象obj
     *
     * @param validObj
     * @param valid
     */
    private void valid(Object validObj, Valid valid) {
        //required
        if (valid.required() && validObj == null) {
            throw new ValidIllegalArgumentException("参数" + valid.name() + "不能为空");
        }

        if (validObj instanceof Number) {
            double num = ((Number) validObj).doubleValue();

            //min
            if (valid.min() != Double.MIN_VALUE && num < valid.min()) {
                throw new ValidIllegalArgumentException("参数" + valid.name() + "最小值是: " + valid.min() + "当前值是: " + num);
            }
            //max
            if (valid.max() != Double.MAX_VALUE && num > valid.max()) {
                throw new ValidIllegalArgumentException("参数" + valid.name() + "最大值是: " + valid.max() + "当前值是: " + num);
            }
        }
        if(validObj instanceof String){
            String str = ((String) validObj);
            //length
            if (valid.length() != -1 && str.length() != valid.length()) {
                throw new ValidIllegalArgumentException("参数" + valid.name() + "字符串长度是: " + valid.length() + "当前值是: " + str.length());
            }
            //maxLen
            if (valid.length() != -1 && str.length() > valid.maxLen()) {
                throw new ValidIllegalArgumentException("参数" + valid.name() + "字符串长度最大值是: " + valid.maxLen() + "当前值是: " + str.length());
            }
            //minLen
            if (valid.length() != -1 && str.length() < valid.minLen()) {
                throw new ValidIllegalArgumentException("参数" + valid.name() + "字符串长度最小值是: " + valid.minLen() + "当前值是: " + str.length());
            }
            //regex
            if(!valid.regex().equals("") && !str.matches(valid.regex())){
                throw new ValidIllegalArgumentException("参数" + valid.name() + "正则匹配规则:" + valid.regex() + "不匹配字符串: " + str.length());
            }
        }

    }

    /**
     * user.order.id 解析出对象id
     *
     * @param name
     * @param requestParamMaps
     * @return
     */
    private Object parseValidObj(String name, Map<String, Object> requestParamMaps) throws InvocationTargetException, IllegalAccessException {
        String[] split = name.split("\\.");
        String rootField = split[0];

        //user.order.id  获取最前面属性的对象 user 后续通过get方法递归调用
        Object root = requestParamMaps.get(rootField);

        if (root == null) {
            //name=a.b.c.d 胡乱写了个不存在的请求参数
            throw new ValidIllegalArgumentException("校验参数不存在 :"+name);
        }

        for (int i = 1, len = split.length; i < len; i++) {
            String field = split[i];
            //user.order.id  获取到getOrder方法
            Method method = null;
            try {
                method = ReflectUtils.getterMethod(root.getClass(), field);
            } catch (NoSuchMethodException e) {
                throw new ValidIllegalArgumentException("校验参数"+name+"不存在此属性:"+field);
            }
            //下一次循环进来root就是order对象
            root = method.invoke(root);

            //user.order.id  如果order==null 则没必要在调用下一个属性了
            if (root == null) {
                return null;
            }
        }

        return root;
    }


}
